/* SPDX-License-Identifier: GPL-2.0
 * smc.h - smc lib of LomboTech SMC module
 *
 * Copyright (C) 2016-2018, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */


#ifndef _SMC_DEF_H_
#define _SMC_DEF_H_

#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/wait.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/types.h>
#include <linux/interrupt.h>

#define SMC_MAJOR	231	/* device major num */

#ifndef SMC_NR_DEVS
#define SMC_NR_DEVS	1	/* device num */
#endif

#define MODULE_NUM	1	/* smc module number */

#define FIFO_DEPTH				(64)	/* smc fifo depth */

/* smc register bit def */
#define SPECIAL_MODE_NORMAL			(0)
#define SPECIAL_MODE_ACTIVATION_AND_COLD_RESET	(1)
#define SPECIAL_MODE_WARM_RESET			(2)
#define SPECIAL_MODE_DEACTIVATION		(3)

#define TRANSFER_MODE_T0			(0)
#define TRANSFER_MODE_T1			(1)

#define T0_RX_PARITY_ERROR			(0)
#define T0_RX_PARITY_ERROR_SAVE_DATA		(1)

#define ATR_FI_DI_DIV				(372)
#define ATR_MAX_CNT				(32 + 1) /* ts + atr */

#define NORMAL_FI_DI_DIV			(32)
#define NORMAL_DATA_CNT				(32)

/* smc status def */
#define FSM_IDLE				(0)
#define FSM_RUN					(1)

/* smc timing def */
#define FSM_OPRATE_TO_CNT			(0xffffffff)
#define FSM_DISABLE_TO_CNT			(0xffff)

/* smc interrupt source def */
#define INT_FSM_FINISH				(1<<0)
#define INT_ATR_FINISH				(1<<4)
#define INT_ATR_TO				(1<<5)
#define INT_IO_STUCK				(1<<6)
#define INT_TCK_ERR				(1<<7)
#define INT_RX_PE				(1<<8)
#define INT_TX_PE				(1<<9)

#define INT_CWT_TO				(1<<12)
#define INT_BWT_TO				(1<<13)

#define INT_TX_EMPTY				(1<<16)
#define INT_RX_FULL				(1<<17)
#define INT_RX_BLOCK_PROLOGUE_RECEIVED		(1<<24)

#define INT_ALL_ERROR				(0x003c07e0)
#define BWT_CNT_200MS				(0x93f6c)

/* smc timeout */
#define DMA_ABORT_CNT				(0x100)

#define to_smc_device(d) container_of(d, struct smc_device, dev)

struct smc_rx {
	u32 rx_cnt;
};

struct contact {
	u8 name[20];
	u8 telephone[20];
};

struct lombo_smc {
	int ic_state;		/* status, 1: have card, 0: no card */
	int state_change;	/* smc status change flags*/
	int irq_no;		/* smc irq number*/
	spinlock_t lock;
	struct mutex m_lock;
	struct work_struct irq_work;
	struct smc_device *smc_dev;
};

struct smc_class_ops {
	int (*read_callback)(struct device *dev, int data);
	int (*irq_enable)(struct device *dev, unsigned int enabled);
};

#define SMC_DEVICE_NAME_SIZE 20
struct smc_device {
	struct device dev;
	struct module *owner;

	int id;
	char name[SMC_DEVICE_NAME_SIZE];
	const struct smc_class_ops *ops;
	struct mutex ops_lock;

	struct cdev char_dev;
	unsigned long flags;

	unsigned long irq_data;
	spinlock_t irq_lock;
	wait_queue_head_t irq_queue;
	struct fasync_struct *async_queue;

	struct smc_task *irq_task;
	spinlock_t irq_task_lock;
	int irq_freq;

	bool registered;
};

struct lombo_smc_clk {
	unsigned int	id;
	unsigned int	io_num;
	char		name[16];
	struct clk	*smc_clk;
	struct clk	*apb_gate;
	struct clk	*apb_reset;
};

extern struct smc_device *smc_device_register(const char *name,
			struct device *dev, const struct smc_class_ops *ops,
			struct module *owner);
extern void smc_device_unregister(struct smc_device *smc);
extern void smc_dev_prepare(struct smc_device *smc);
extern void smc_dev_add_device(struct smc_device *smc);
extern void smc_dev_del_device(struct smc_device *smc);
extern void smc_proc_add_device(struct smc_device *smc);
extern void smc_proc_del_device(struct smc_device *smc);
extern const struct attribute_group **smc_get_dev_attribute_groups(void);
extern void smc_dev_init(void);
extern void smc_dev_exit(void);

extern void __iomem *get_smc_base_addr(void);

extern void smc_detect(struct platform_device *pdev);
extern int smc_gpio_get(struct platform_device *pdev);
extern void smc_set_pin_input(unsigned int val);
extern void smc_set_pin_output(unsigned int val);
extern int smc_select_gpio_state(struct pinctrl *pctrl, char *name, u32 no);
extern void smc_irq_handle(void);
extern void smc_common_int_process(void);
extern int smc_wait_fsm_finished(void);
extern int smc_warm_reset(void);
extern int smc_activation_and_cold_reset(void);
extern int smc_deactivation_mode(void);
extern int smc_normal_mode(void);
extern int smc_stop_clk(void);
extern int smc_release_all(void);
extern int smc_t0_data_exchange(u64 tx_buf, u32 tx_cnt, u64 rx_buf,
				struct smc_rx *rx);
extern int smc_pps_exchange(void);

extern int smc_get_iccid(void);
extern int smc_get_imsi(void);
extern int smc_get_lp(void);
extern int smc_write_lp(u8 *data);
extern int smc_get_contact(u32 num);
extern int smc_write_contact(struct contact data, u32 num);
extern int smc_get_message(u32 num);
extern int smc_write_message(u8 *message, u32 num);
extern int smc_clear_message(u32 num);

extern int smc_read_specail_operation(void);
extern int smc_set_specail_operation(int mode);
extern int smc_read_transfer_mode(void);
extern int smc_set_transfer_mode(int mode);
extern int smc_read_stop_clk_enable(void);
extern int smc_set_stop_clk_enable(int mode);
extern int smc_read_block_edc_type(void);
extern int smc_set_block_edc_type(int mode);
extern int smc_read_start_status(void);

#endif /*SMC*/
